package com.ruoyi.es.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.es.domain.CategoryCountAgg;
import com.ruoyi.es.domain.EsResponse;
import com.ruoyi.es.domain.SkuInfoEsModel;
import com.ruoyi.es.query.SearchQuery;
import com.ruoyi.es.result.SearchResult;
import com.ruoyi.es.service.IEsService;

import org.apache.commons.lang3.StringUtils;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.nested.NestedAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.nested.ParsedNested;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedLongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.Avg;
import org.elasticsearch.search.aggregations.metrics.AvgAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.Sum;
import org.elasticsearch.search.aggregations.metrics.SumAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.xcontent.XContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.swing.text.Highlighter;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * @author lemon
 * @date 2024/12/17 16:13
 **/
@Service
public class EsServiceImpl implements IEsService {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Override
    public boolean addBatch(String data) {
        List<SkuInfoEsModel> list = JSONArray.parseArray(data, SkuInfoEsModel.class);
        BulkRequest bulkRequest = new BulkRequest();
        list.stream().forEach(esModel -> {
            IndexRequest indexRequest = new IndexRequest();
            indexRequest.index("product");
            indexRequest.id(esModel.getSkuId().toString());
            indexRequest.source(JSONObject.toJSONString(esModel), XContentType.JSON);
            bulkRequest.add(indexRequest);
        });
        BulkResponse bulk = null;
        try {
            bulk = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return bulk.hasFailures();
    }

    @Override
    public SearchResult search(SearchQuery searchQuery) throws IOException {

        //1. 构建searchRequest
        SearchRequest searchRequest = buildSearchRequest(searchQuery);

        //2. 执行search
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        //3. 解析response
        return analyzeResponse(searchResponse,searchQuery);
    }


    private SearchRequest buildSearchRequest(SearchQuery searchQuery) {
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        //1.1 keyword
        if(StringUtils.isNotEmpty(searchQuery.getKeyword())) {
            boolQueryBuilder.must(QueryBuilders.matchQuery("skuTitle",searchQuery.getKeyword()));
        }
        //1.2 catalog

        if(searchQuery.getCatalog3Id()!=null) {
            boolQueryBuilder.filter(QueryBuilders.termQuery("catalogId",searchQuery.getCatalog3Id()));
        }
        //1.3 brandId

        if(searchQuery.getBrandId()!=null && searchQuery.getBrandId().size()>0){
            boolQueryBuilder.filter(QueryBuilders.termsQuery("brandId",searchQuery.getBrandId()));
        }
        //1.4 skuPrice  10_20000
        if (StringUtils.isNotBlank(searchQuery.getSkuPrice())){
            RangeQueryBuilder skuPrice = QueryBuilders.rangeQuery("skuPrice");

            String[] prices = searchQuery.getSkuPrice().split("_");
            if(prices.length==2){
                skuPrice.lte(prices[1]);
                skuPrice.gte(prices[0]);
            }else if(searchQuery.getSkuPrice().startsWith("_")){
                skuPrice.lte(prices[1]);
            }else if(searchQuery.getSkuPrice().endsWith("_")){
                skuPrice.gte(prices[0]);
            }
            boolQueryBuilder.filter(skuPrice);
        }

        //1.5  nested  attrs   1_3:3&2_4:8

        /*if(searchQuery.getAttrs()!=null && searchQuery.getAttrs().size()>0){

            for (String attrStr : searchQuery.getAttrs()) {

                String[] s = attrStr.split("_");
                String attrId = s[0];

                String[] sttrValues = s[1].split(":");

                BoolQueryBuilder boolNestedQueryBuilder = QueryBuilders.boolQuery();
                boolNestedQueryBuilder.must(QueryBuilders.termQuery("attrs.attrId",attrId));
                boolNestedQueryBuilder.must(QueryBuilders.termQuery("attrs.attrValue",sttrValues));

                NestedQueryBuilder attrs = QueryBuilders.nestedQuery("attrs", boolNestedQueryBuilder, ScoreMode.None);
                boolQueryBuilder.filter(attrs);
            }
        }*/
        sourceBuilder.query(boolQueryBuilder);


        //1.4 sort  saleCount_desc

        if(StringUtils.isNotBlank(searchQuery.getSort())){
            String[] strings = searchQuery.getSort().split("_");

            sourceBuilder.sort(strings[0],"asc".equalsIgnoreCase(strings[1])? SortOrder.ASC:SortOrder.DESC);
        }

        //1.6 分页
        sourceBuilder.from((searchQuery.getPageNum()-1)*5);
        sourceBuilder.size(5);

        //1.7 高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("skuTitle");
        highlightBuilder.preTags("<span style='color:skyblue'>");
        highlightBuilder.postTags("</span>");

        sourceBuilder.highlighter(highlightBuilder);

        //1.8  aggs
        TermsAggregationBuilder brandIdAgg = AggregationBuilders.terms("brandIdAgg").field("brandId");
        TermsAggregationBuilder brandNameAgg = AggregationBuilders.terms("brandNameAgg").field("brandName");
        brandIdAgg.subAggregation(brandNameAgg);

        TermsAggregationBuilder catalogIdAgg = AggregationBuilders.terms("catalogIdAgg").field("catalogId");
        TermsAggregationBuilder catalogNameAgg = AggregationBuilders.terms("catalogNameAgg").field("catalogName");
        catalogIdAgg.subAggregation(catalogNameAgg);


        NestedAggregationBuilder nested = AggregationBuilders.nested("attrsAgg", "attrs");
        TermsAggregationBuilder attrIdAgg = AggregationBuilders.terms("attrIdAgg").field("attrs.attrId");
        TermsAggregationBuilder attrNameAgg = AggregationBuilders.terms("attrNameAgg").field("attrs.attrName");
        TermsAggregationBuilder attrValueAgg = AggregationBuilders.terms("attrValueAgg").field("attrs.attrValue");

        nested.subAggregation(attrIdAgg);
        attrIdAgg.subAggregation(attrNameAgg);
        attrIdAgg.subAggregation(attrValueAgg);

        sourceBuilder.aggregation(brandIdAgg);
        sourceBuilder.aggregation(catalogIdAgg);
        sourceBuilder.aggregation(nested);

        SearchRequest searchRequest = new SearchRequest();
        searchRequest.indices("product");
        searchRequest.source(sourceBuilder);
        return searchRequest;
    }


    private SearchResult analyzeResponse(SearchResponse searchResponse,SearchQuery searchQuery) {
        SearchResult searchResult =  new SearchResult();


        SearchHits hits = searchResponse.getHits();

        //查询到的所有商品信息
        List<SkuInfoEsModel> skuEsModelList = new ArrayList<>();
        for (SearchHit hit : hits.getHits()) {

            String skuEsModelString = hit.getSourceAsString();
            SkuInfoEsModel skuEsModel = JSON.parseObject(skuEsModelString, SkuInfoEsModel.class);

            // 处理高亮
            if(StringUtils.isNotBlank(searchQuery.getKeyword())){
                Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                HighlightField skuTitleHighlightField = highlightFields.get("skuTitle");


                skuEsModel.setSkuTitle(skuTitleHighlightField.getFragments()[0].toString());

            }

            skuEsModelList.add(skuEsModel);

        }

        searchResult.setProducts(skuEsModelList);
        //当前页码

        searchResult.setPageNum(searchQuery.getPageNum());
        //总记录数

        searchResult.setTotal(hits.getTotalHits().value);
        //总页码数
        searchResult.setTotalPages(
                Long.valueOf(searchResult.getTotal()%5==0?searchResult.getTotal()/5:(searchResult.getTotal()/5+1)).intValue()
        );


        Aggregations aggregations = searchResponse.getAggregations();
        //当前查询到的结果, 所有涉及到的品牌

        ParsedLongTerms brandIdAgg = aggregations.get("brandIdAgg");
        List<? extends Terms.Bucket> buckets = brandIdAgg.getBuckets();
        List<SearchResult.BrandVo> brandVos = new ArrayList<>();
        for (Terms.Bucket bucket : buckets) {
            SearchResult.BrandVo brandVo = new SearchResult.BrandVo();
            brandVo.setBrandId(Long.valueOf(bucket.getKeyAsString()));

            Terms brandNameAgg = bucket.getAggregations().get("brandNameAgg");
            String brandName = brandNameAgg.getBuckets().get(0).getKeyAsString();
            brandVo.setBrandName(brandName);

            brandVos.add(brandVo);
        }
        searchResult.setBrands(brandVos);
        //当前查询到的结果, 所有涉及到的分类

        List<SearchResult.CatalogVo> catalogs = new ArrayList<>();
        ParsedLongTerms catalogIdAgg = aggregations.get("catalogIdAgg");

        List<? extends Terms.Bucket> catalogBuckets = catalogIdAgg.getBuckets();

        for (Terms.Bucket catalogBucket : catalogBuckets) {
            SearchResult.CatalogVo catalogVo = new SearchResult.CatalogVo();
            String catalogId = catalogBucket.getKeyAsString();
            catalogVo.setCatalogId(Long.valueOf(catalogId));
            Terms catalogNameAgg = catalogBucket.getAggregations().get("catalogNameAgg");
            String catalogName = catalogNameAgg.getBuckets().get(0).getKeyAsString();
            catalogVo.setCatalogName(catalogName);
            catalogs.add(catalogVo);
        }
        searchResult.setCatalogs(catalogs);
        //当前查询的结果 所有涉及到所有属性
        List<SearchResult.AttrVo> attrs = new ArrayList<>();
        ParsedNested attrsAgg = aggregations.get("attrsAgg");
        Terms attrIdAgg = attrsAgg.getAggregations().get("attrIdAgg");

        for (Terms.Bucket bucket : attrIdAgg.getBuckets()) {
            SearchResult.AttrVo attrVo = new SearchResult.AttrVo();
            //attrId
            String attrId = bucket.getKeyAsString();
            attrVo.setAttrId(Long.valueOf(attrId));

            Aggregations attrIdBucketAggregations = bucket.getAggregations();
            //attrName
            Terms attrNameAgg = attrIdBucketAggregations.get("attrNameAgg");
            String attrName = attrNameAgg.getBuckets().get(0).getKeyAsString();
            attrVo.setAttrName(attrName);
            //attrValues  []
            Terms attrValueAgg = attrIdBucketAggregations.get("attrValueAgg");
            List<String> values = new ArrayList<>();
            for (Terms.Bucket attrValueAggBucket : attrValueAgg.getBuckets()) {
                values.add(attrValueAggBucket.getKeyAsString());
            }
            attrVo.setAttrValue(values);

            attrs.add(attrVo);

        }
        searchResult.setAttrs(attrs);

        return searchResult;
    }
    /*private SearchRequest builderRequest(SearchQuery searchQuery) {

        SearchSourceBuilder builder = new SearchSourceBuilder();

        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        boolQueryBuilder.must(QueryBuilders.matchQuery("skuTitle","华为手机"));

        boolQueryBuilder.filter(QueryBuilders.termsQuery("brandId", Arrays.asList(1,2)));
        boolQueryBuilder.filter(QueryBuilders.termQuery("catalogId",255));

        BoolQueryBuilder attrQueryBuilder1 = QueryBuilders.boolQuery();
        attrQueryBuilder1.must(QueryBuilders.termQuery("attrs.attrId",1));
        attrQueryBuilder1.must(QueryBuilders.termsQuery("attrs.attrValue",Arrays.asList("5G","6G")));
        boolQueryBuilder.filter(QueryBuilders.nestedQuery("attrs",attrQueryBuilder1, ScoreMode.None));


        BoolQueryBuilder attrQueryBuilder2 = QueryBuilders.boolQuery();
        attrQueryBuilder2.must(QueryBuilders.termQuery("attrs.attrId",3));
        attrQueryBuilder2.must(QueryBuilders.termsQuery("attrs.attrValue",Arrays.asList("流光幻镜","skyblue")));
        boolQueryBuilder.filter(QueryBuilders.nestedQuery("attrs",attrQueryBuilder2, ScoreMode.None));

        RangeQueryBuilder skuPriceBuilder = QueryBuilders.rangeQuery("skuPrice");
        skuPriceBuilder.gte(10);
        skuPriceBuilder.lte(20000);
        boolQueryBuilder.filter(skuPriceBuilder);

        builder.query(boolQueryBuilder);

        builder.from(0);
        builder.size(20);

        builder.sort("skuPrice", SortOrder.DESC);

        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("skuTitle");
        highlightBuilder.preTags("<span style='color:skyblue'>");
        highlightBuilder.postTags("</span>");

        builder.highlighter(highlightBuilder);

        *//*TermsAggregationBuilder brandIdAgg = AggregationBuilders.terms("brandIdAgg").field("brandId");
        TermsAggregationBuilder brandNameAgg = AggregationBuilders.terms("brandNameAgg").field("brandName");
        TermsAggregationBuilder brandImgAgg = AggregationBuilders.terms("brandImgAgg").field("brandImg");
        brandIdAgg.subAggregation(brandNameAgg);
        brandIdAgg.subAggregation(brandImgAgg);
        builder.aggregation(brandIdAgg);

        TermsAggregationBuilder catalogIdAgg = AggregationBuilders.terms("catalogIdAgg").field("catalogId");
        TermsAggregationBuilder catalogNameAgg = AggregationBuilders.terms("catalogNameAgg").field("catalogName");
        catalogIdAgg.subAggregation(catalogNameAgg);
        builder.aggregation(catalogIdAgg);

        NestedAggregationBuilder attrAgg = AggregationBuilders.nested("attrAgg", "attrs");
        TermsAggregationBuilder attrIdAgg = AggregationBuilders.terms("attrIdAgg").field("attrs.attrId");
        TermsAggregationBuilder attrNameAgg = AggregationBuilders.terms("attrNameAgg").field("attrs.attrName");
        TermsAggregationBuilder attrValueAgg = AggregationBuilders.terms("attrValueAgg").field("attrs.attrValue");
        attrAgg.subAggregation(attrIdAgg);
        attrIdAgg.subAggregation(attrNameAgg);
        attrIdAgg.subAggregation(attrValueAgg);

        builder.aggregation(attrAgg);
*//*

        SearchRequest request = new SearchRequest();
        request.indices("product");
        request.source(builder);

        return request;
    }*/

}
